﻿using BUGCOME.Infrastructure.Extensions;
using BUGCOME.Infrastructure.Model;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using MiniExcelLibs;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System.Web;

namespace BUGCOME.Infrastructure.Controllers
{
    /// <summary>
    /// 控制器基类，提供统一的API响应封装、JSON序列化配置及通用响应处理方法
    /// 所有业务控制器应继承此类，以保证系统响应格式的一致性
    /// </summary>
    public class BaseController : ControllerBase
    {
        /// <summary>
        /// 默认完整时间格式字符串，用于JSON序列化时的日期时间格式化
        /// 格式：年-月-日 时:分:秒
        /// </summary>
        public static string TimeFormatFull = "yyyy-MM-dd HH:mm:ss";

        /// <summary>
        /// 返回成功类型的API响应
        /// </summary>
        /// <param name="data">响应数据（可为null）</param>
        /// <param name="timeFormatStr">时间格式化字符串，默认使用TimeFormatFull</param>
        /// <returns>包含格式化JSON的IActionResult，数据存在时状态为SUCCESS，否则为NO_DATA</returns>
        protected IActionResult Success(object data, string timeFormatStr = "yyyy-MM-dd HH:mm:ss")
        {
            // 根据数据是否为空选择对应的结果码
            var resultCode = data != null ? ResultCode.SUCCESS : ResultCode.NO_DATA;
            string jsonStr = GetJsonStr(GetApiResult(resultCode, data), timeFormatStr);
            return Content(jsonStr, "application/json");
        }

        /// <summary>
        /// 将ApiResult对象转换为标准化JSON响应
        /// </summary>
        /// <param name="apiResult">已构建的ApiResult对象</param>
        /// <returns>包含格式化JSON的IActionResult</returns>
        protected IActionResult ToResponse(ApiResult apiResult)
        {
            string jsonStr = GetJsonStr(apiResult, TimeFormatFull);
            return Content(jsonStr, "application/json");
        }

        /// <summary>
        /// 根据操作影响的行数返回标准化响应
        /// </summary>
        /// <param name="rows">数据库操作受影响的行数</param>
        /// <param name="timeFormatStr">时间格式化字符串，默认使用TimeFormatFull</param>
        /// <returns>行数>0时返回成功响应，否则返回失败响应</returns>
        protected IActionResult ToResponse(long rows, string timeFormatStr = "yyyy-MM-dd HH:mm:ss")
        {
            string jsonStr = GetJsonStr(ToJson(rows), timeFormatStr);
            return Content(jsonStr, "application/json");
        }

        /// <summary>
        /// 根据结果码和自定义消息返回标准化响应
        /// </summary>
        /// <param name="resultCode">结果状态码枚举</param>
        /// <param name="msg">自定义响应消息（为空时使用枚举默认描述）</param>
        /// <returns>包含指定状态和消息的JSON响应</returns>
        protected IActionResult ToResponse(ResultCode resultCode, string msg = "")
        {
            return ToResponse(new ApiResult((int)resultCode, msg));
        }

        /// <summary>
        /// 导出Excel
        /// </summary>
        /// <param name="path">完整文件路径</param>
        /// <param name="fileName">带扩展文件名</param>
        /// <returns></returns>
        protected IActionResult ExportExcel(string path, string fileName)
        {
            //var webHostEnvironment = App.WebHostEnvironment;
            if (!Path.Exists(path))
            {
                throw new CustomException(fileName + "文件不存在");
            }
            var stream = System.IO.File.OpenRead(path);  //创建文件流

            Response.Headers.Append("Access-Control-Expose-Headers", "Content-Disposition");
            return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", HttpUtility.UrlEncode(fileName));
        }

        /// <summary>
        /// 导出Excel
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="sheetName"></param>
        /// <param name="fileName"></param>
        protected string ExportExcel<T>(List<T> list, string sheetName, string fileName)
        {
            return ExportExcelMini(list, sheetName, fileName).Item1;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <param name="sheetName"></param>
        /// <param name="fileName"></param>
        /// <returns></returns>
        protected (string, string) ExportExcelMini<T>(List<T> list, string sheetName, string fileName)
        {
            IWebHostEnvironment webHostEnvironment = (IWebHostEnvironment)App.ServiceProvider.GetService(typeof(IWebHostEnvironment));
            string sFileName = $"{fileName}_{DateTime.Now:MMdd-HHmmss}.xlsx";
            string fullPath = Path.Combine(webHostEnvironment.WebRootPath, "export", sFileName);

            Directory.CreateDirectory(Path.GetDirectoryName(fullPath));

            MiniExcel.SaveAs(fullPath, list, sheetName: sheetName);
            return (sFileName, fullPath);
        }

        /// <summary>
        /// 下载导入模板
        /// </summary>
        /// <typeparam name="T">数据类型</typeparam>
        /// <param name="list">空数据类型集合</param>
        /// <param name="fileName">下载文件名</param>
        /// <returns></returns>
        protected (string, string) DownloadImportTemplate<T>(List<T> list, string fileName)
        {
            IWebHostEnvironment webHostEnvironment = App.WebHostEnvironment;
            string sFileName = $"{fileName}.xlsx";
            string fullPath = Path.Combine(webHostEnvironment.WebRootPath, "ImportTemplate", sFileName);

            //不存在模板创建模板
            if (!Directory.Exists(fullPath))
            {
                Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
            }
            if (!Path.Exists(fullPath))
            {
                MiniExcel.SaveAs(fullPath, list, overwriteFile: true);
            }
            return (sFileName, fullPath);
        }


        #region 私有工具方法

        /// <summary>
        /// 根据受影响行数构建ApiResult
        /// </summary>
        /// <param name="rows">受影响行数</param>
        /// <param name="data">附加数据（可选）</param>
        /// <returns>行数>0时返回成功ApiResult，否则返回失败ApiResult</returns>
        protected ApiResult ToJson(long rows, object? data = null)
        {
            return rows > 0
                ? ApiResult.Success("success", data)
                : GetApiResult(ResultCode.FAIL);
        }

        /// <summary>
        /// 构建ApiResult对象
        /// </summary>
        /// <param name="resultCode">结果状态码</param>
        /// <param name="data">响应数据（可选）</param>
        /// <returns>包含状态码、消息和数据的ApiResult</returns>
        protected ApiResult GetApiResult(ResultCode resultCode, object? data = null)
        {
            // 获取枚举的描述信息作为响应消息
            var msg = resultCode.GetDescription();
            return new ApiResult((int)resultCode, msg, data);
        }

        /// <summary>
        /// 将ApiResult序列化为JSON字符串（内部使用）
        /// </summary>
        /// <param name="apiResult">待序列化的ApiResult对象</param>
        /// <param name="timeFormatStr">时间格式化字符串</param>
        /// <returns>格式化后的JSON字符串（驼峰命名+指定时间格式）</returns>
        private static string GetJsonStr(ApiResult apiResult, string timeFormatStr)
        {
            // 确保时间格式不为空，默认使用完整格式
            if (string.IsNullOrEmpty(timeFormatStr))
            {
                timeFormatStr = TimeFormatFull;
            }

            // JSON序列化配置：驼峰命名+指定时间格式+缩进排版
            var serializerSettings = new JsonSerializerSettings
            {
                ContractResolver = new CamelCasePropertyNamesContractResolver(),
                DateFormatString = timeFormatStr,
                Formatting = Formatting.Indented
            };

            return JsonConvert.SerializeObject(apiResult, serializerSettings);
        }
        #endregion
    }
}